package com.tsj.spzx.log.aspect;

import com.tsj.spzx.log.annotation.Log;
import com.tsj.spzx.log.service.SysOperService;
import com.tsj.spzx.log.utils.LogUtil;
import com.tsj.spzx.model.entity.system.SysOperLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class LogAspect {

    // 注入service
    @Autowired
    private SysOperService sysOperService;

    // 环绕通知
    @Around("@annotation(sysLog)")  // @annotation(sysLog)：表示拦截所有标有sysLog参数指定注解的方法
    public Object recordLog(ProceedingJoinPoint joinPoint, Log sysLog){

       // String title = sysLog.title();       // 获取到模块名称
       //log.info("LogAspect...doAroundAdvice方法执行了: " + title);

        // 最后的数据都会封装在 SysOperLog中
        SysOperLog sysOperLog = new SysOperLog();
        // 在前执行，先进行一次数据封装
        LogUtil.beforeHandleLog(sysLog, joinPoint, sysOperLog);

        Object proceed = null;
        try {
            // 业务方法执行
            proceed = joinPoint.proceed();

            // 业务方法执行之后,在进行一次数据封装
          // log.info("LogAspect...doAroundAdvice方法已经执行了.... " + proceed);
            // 这个是无异常的，status为0
            LogUtil.afterHandleLog(sysLog, proceed, sysOperLog, 0, null);
        } catch (Throwable throwable) {
            // 有异常的情况下 status为1
            LogUtil.afterHandleLog(sysLog, proceed, sysOperLog, 1, throwable.getMessage());
            // 打印异常，并抛出异常
            throwable.printStackTrace();
            /**
             * 异常必须抛出，如果不抛出异常，当service添加了事务，事务不会回滚
             * reason:
             *      当service业务层发生了异常，被切面拦截后，切面如果不抛出，@Transactional就感知不到异常，就不会回滚事务
             */
            throw new RuntimeException(throwable);
        }

        // 日志信息都已封装在sysOperLog中，设置service，mapper方法将其存入数据库
        sysOperService.save(sysOperLog);

        return proceed;
    }
}
